#!/usr/bin/python3
# -*- coding: UTF-8 -*-

# Copyright (C) 2025 Huawei Technologies Co., Ltd. All rights reserved.

import os
import re
import sys
import time
import logging
import subprocess
import argparse

from src.libexec.openubmc.getInfoForBlade import InfoHandler as bladeInfoHandler
from src.libexec.openubmc.getInfo import InfoHandler as rackInfoHandler
from src.libexec.openubmc.getInfoForBlade import MSG_HEASTATUS

logging.basicConfig(format="%(message)s")

STATUS_UNKNOWN = 3
COMPONENT_POWER = "power"
COMPONENT_BLADE = "blade"
COMPONENT_FAN = "fan"
COMPONENT_SYS = "system"
COMPONENT_SWI = "switch"
COMPONENT_SMM = "smm"
COMPONENT_SHELF = "shelf"
COMPONENT_CPU = "cpu"
COMPONENT_MEMORY = "memory"
COMPONENT_DISK = "hardDisk"
COMPONENT_RAID = "raid"


def findNagiosDir():
    """return nagios directory"""
    return os.environ.get("NAGIOSHOME", "/usr/local/nagios")


nagiosHome = findNagiosDir()
genkeyPath = nagiosHome + os.path.sep + "bin" + os.path.sep + "openubmc"
sys.path.append(genkeyPath)

TRAP_BINDING_VALUE_SEP = "[,;/-]"
BINDING_KEY_VALUE_SEP = ":"
CMD_FILE_NAME_SEP = "_"
CMD_FILE_CONTENT_SEP = "&"
NAGIOS_CMD_SEP = ";"
NAGIOS_CMD_SIGN = "PROCESS_SERVICE_CHECK_RESULT"
NAGIOS_CMD_TIMESTAMP_SURROUND_LEFT = "["
NAGIOS_CMD_TIMESTAMP_SURROUND_RIGHT = "]"


def constructMessage(host, service, status, info):
    return (
        NAGIOS_CMD_TIMESTAMP_SURROUND_LEFT
        + str(time.time())
        + NAGIOS_CMD_TIMESTAMP_SURROUND_RIGHT
        + " "
        + NAGIOS_CMD_SIGN
        + NAGIOS_CMD_SEP
        + host
        + NAGIOS_CMD_SEP
        + service
        + NAGIOS_CMD_SEP
        + str(status)
        + NAGIOS_CMD_SEP
        + info
        + "\n"
    )


def getCmdfilePath():
    initfilePath = (
        os.path.normpath(sys.path[0])
        + "/../.."
        + os.path.sep
        + "etc"
        + os.path.sep
        + "openubmc/initial.cfg"
    )
    with open(initfilePath) as initialCfg:
        for pro in initialCfg:
            if re.findall(r"^\s*nagios_cmd_file\s*=\s*/", pro):
                nagioscmdFile = re.sub(r"\s*$", "", pro.split("=")[1])
        if nagioscmdFile is not None:
            return nagioscmdFile
        else:
            return None


def writeCmd(host, service, status, info):
    file = None
    try:
        file = open(getCmdfilePath(), "a")
        nagioscmd = constructMessage(host, service, status, info)
        file.write(nagioscmd)
    except Exception as err:
        logging.error("writeCmd error: " + str(err))
    finally:
        if file is not None:
            file.close()


def dencrypt(inputStr):
    from src.bin.openubmc.genKey import readKey
    from src.bin.openubmc.genKey import genRootKeyStr
    from src.bin.openubmc.genKey import dencryptKey

    k = dencryptKey(readKey(), genRootKeyStr())
    decryotStr = dencryptKey(inputStr, k)

    if decryotStr is None:
        return ""
    else:
        return decryotStr


def commandParse():
    parser = argparse.ArgumentParser(add_help=True)
    parser.add_argument(
        "-c",
        "--component",
        dest="component",
        help="component for check  as (hardDisk,cpu,memory,power,cpu,memory,fan,system,hardDisk)",
        default="system",
    )
    parser.add_argument(
        "-H",
        "--host",
        dest="host",
        help="Hostname or IP address of the host to check",
        default=None,
    )
    parser.add_argument(
        "-v",
        "--version",
        dest="version",
        help="SNMP Version to use (1, 2c or 3)",
        default="3",
    )
    parser.add_argument(
        "-u",
        "--user",
        dest="user",
        help="SNMP username (only with SNMP v3)",
        default=None,
    )
    parser.add_argument(
        "-C",
        "--community",
        dest="community",
        help="SNMP Community (only with SNMP v1|v2c)",
        default=None,
    )
    parser.add_argument("-p", "--port", dest="port", help="port for SNMP", default="161")
    parser.add_argument(
        "-A",
        "--apwd",
        dest="apwd",
        help="SNMP authentication password (only with SNMP v3)",
        default=None,
    )
    parser.add_argument(
        "-a",
        "--aprotocol",
        dest="aprotocol",
        help="SNMP authentication protocol (SHA only with SNMP v3)",
        default="SHA",
    )
    parser.add_argument(
        "-X",
        "--ppwd",
        dest="ppwd",
        help="SNMP privacy password (only with SNMP v3)",
        default=None,
    )
    parser.add_argument(
        "-x",
        "--pprotocol",
        dest="pprotocol",
        help="SNMP privacy protocol AES||DES (only with SNMP v3)",
        default="AES",
    )
    parser.add_argument(
        "-l",
        "--seclevel",
        dest="seclevel",
        help="SNMP security level (only with SNMP v3) (noAuthNoPriv|authNoPriv|authPriv)",
        default="authPriv",
    )
    parser.add_argument(
        "-t",
        "--timeout",
        dest="timeout",
        help="Timeout in seconds for SNMP",
        default="10",
    )
    parser.add_argument(
        "-T",
        "--type",
        dest="type",
        help="service types as (blade, rack)",
        default="blade",
    )
    parser.add_argument(
        "-r",
        "--retry",
        dest="retry",
        help="Timeout in seconds for SNMP",
        default="2",
    )

    opts = parser.parse_args()

    compenlist = [
        COMPONENT_POWER,
        COMPONENT_FAN,
        COMPONENT_SYS,
        COMPONENT_SWI,
        COMPONENT_SMM,
        COMPONENT_SHELF,
        COMPONENT_BLADE,
    ]
    if opts.type.upper() == "RACK" or opts.type.upper() == "HIGHDENSITY":
        compenlist = [
            COMPONENT_POWER,
            COMPONENT_FAN,
            COMPONENT_SYS,
            COMPONENT_CPU,
            COMPONENT_MEMORY,
            COMPONENT_DISK,
            COMPONENT_RAID,
        ]
    if opts.host is None:
        logging.error("please input Hostname or IP")
        raise Exception("HostName or IP is null")
    if opts.version == "3" and opts.user is None:
        logging.error("please input SNMP username")
        raise Exception("SNMP user is null")
    if opts.ppwd is None:
        opts.ppwd = opts.apwd
    if opts.component not in compenlist:
        logging.error("-c only support as : ")
        for eachitem in compenlist:
            logging.error(eachitem)
        raise Exception("Invalid component")
    if opts.apwd is not None:
        opts.apwd = dencrypt(opts.apwd)
    if opts.ppwd is not None:
        opts.ppwd = dencrypt(opts.ppwd)
    if opts.community is not None:
        opts.community = dencrypt(opts.community)

    return opts


if __name__ == "__main__":
    try:
        opts = commandParse()
    except Exception:
        exit(STATUS_UNKNOWN)

    try:
        if opts.type.lower() == "blade":
            infoHandler = bladeInfoHandler(opts)
            status, info = infoHandler.getAllStatus(infoHandler.parm.component)
            writeCmd(
                infoHandler.parm.host,
                infoHandler.parm.component.lower(),
                status,
                (
                    "%s HealthStatus: %s "
                    % (str(infoHandler.parm.component), MSG_HEASTATUS[status])
                )
                + info.replace("\n", "===="),
            )
        else:
            infoHandler = rackInfoHandler(opts)
            status, info = infoHandler.getRaidStatus()

        logging.error("%s HealthStatus: %s " % (str(infoHandler.parm.component), MSG_HEASTATUS[status]))
        logging.error("=============================== info =============================")
        logging.error(info)
        exit(status)
    except Exception as e:
        logging.error("Unhandled exception while running script: %s" % e)
        exit(STATUS_UNKNOWN)
